Atraskite tvirtą API kūrimą su FastAPI ir Pydantic. Išmokite įdiegti galingą, automatinį užklausų validavimą, tvarkyti klaidas ir kurti keičiamo dydžio programas.
FastAPI užklausų validavimas su Pydantic modeliais: išsamus vadovas
Šiuolaikinio žiniatinklio kūrimo pasaulyje tvirtų ir patikimų API kūrimas yra nepaprastai svarbus. Kritinis šio tvirtumo komponentas yra duomenų validavimas. Be jo, esate pažeidžiami seno principo "Šlamštas įeina, šlamštas išeina", o tai veda prie klaidų, saugumo spragų ir prastos kūrėjo patirties jūsų API vartotojams. Būtent čia suspindi galingas FastAPI ir Pydantic derinys, paverčiantis tai, kas anksčiau buvo nuobodi užduotis, elegantišku, automatizuotu procesu.
FastAPI, didelio našumo Python žiniatinklio karkasas, įgijo didžiulį populiarumą dėl savo greičio, paprastumo ir kūrėjams patogių funkcijų. Jo magijos širdyje slypi gilus integravimas su Pydantic – duomenų validavimo ir nustatymų valdymo biblioteka. Kartu jie suteikia vientisą, tipams saugų ir save dokumentuojantį būdą kurti API.
Šis išsamus vadovas padės jums giliau pažvelgti į Pydantic modelių naudojimą užklausų validavimui FastAPI. Nesvarbu, ar esate pradedantysis, tik pradedantis dirbti su API, ar patyręs kūrėjas, siekiantis supaprastinti savo darbo eigą, rasite praktinių įžvalgų ir pavyzdžių, kad įvaldytumėte šį esminį įgūdį.
Kodėl užklausų validavimas yra itin svarbus šiuolaikinėms API?
Prieš pereidami prie kodo, išsiaiškinkime, kodėl įvesties validavimas nėra tik "maloni savybė" – tai esminė būtinybė. Tinkamas užklausų validavimas atlieka kelias svarbias funkcijas:
- Duomenų vientisumas: Užtikrina, kad į jūsų sistemą patenkantys duomenys atitinka numatomą struktūrą, tipus ir apribojimus. Tai apsaugo nuo neteisingai suformuotų duomenų, galinčių sugadinti jūsų duomenų bazę arba sukelti netikėtą programos elgesį.
- Sauga: Validuojant ir sanitarizuojant visus gaunamus duomenis, sukuriate pirmąją gynybos liniją nuo įprastų saugumo grėsmių, tokių kaip NoSQL/SQL injekcijos, tarp svetainių skriptai (XSS) ir kitos užklausų pagrindu atliekamos atakos.
- Kūrėjo patirtis (DX): API vartotojams (įskaitant ir jūsų frontend komandas) aiškus ir nedelsiamas atsiliepimas apie neteisingas užklausas yra neįkainojamas. Vietoj bendros 500 serverio klaidos, gerai patvirtinta API grąžina tikslią 422 klaidą, išsamiai nurodydama, kurie laukai yra neteisingi ir kodėl.
- Tvirtumas ir patikimumas: Duomenų validavimas programos įvesties taške neleidžia neteisingiems duomenims sklisti giliai į jūsų verslo logiką. Tai žymiai sumažina vykdymo metu pasitaikančių klaidų tikimybę ir daro jūsų kodo bazę nuspėjamesnę ir lengviau derinamą.
Galingas duetas: FastAPI ir Pydantic
FastAPI ir Pydantic sinergija yra tai, kas daro karkasą tokį patrauklų. Išnagrinėkime jų vaidmenis:
- FastAPI: Modernus žiniatinklio karkasas, kuris naudoja standartinius Python tipų užuominas API parametrams ir užklausų kūnams apibrėžti. Jis pastatytas ant Starlette dideliam našumui ir ASGI asinchroninėms galimybėms.
- Pydantic: Biblioteka, kuri naudoja tas pačias Python tipų užuominas duomenų validavimui, serializavimui (duomenų konvertavimui į ir iš formatų, tokių kaip JSON) ir nustatymų valdymui. Jūs apibrėžiate savo duomenų "formą" kaip klasę, kuri paveldi iš Pydantic `BaseModel`.
Kai naudojate Pydantic modelį užklausos kūnui deklaruoti FastAPI kelio operacijoje, karkasas automatiškai orkestruoja šiuos veiksmus:
- Perskaito gaunamą JSON užklausos kūną.
- Analizuoja JSON ir perduoda duomenis jūsų Pydantic modeliui.
- Pydantic validuoja duomenis pagal jūsų modelyje apibrėžtus tipus ir apribojimus.
- Jei galioja, sukuria jūsų modelio egzempliorių, suteikdamas jums visiškai tipizuotą Python objektą, su kuriuo galite dirbti savo funkcijose, su automatinio užbaigimo galimybe jūsų redaktoriuje.
- Jei negalioja, FastAPI pagauna Pydantic `ValidationError` ir automatiškai grąžina išsamų JSON atsakymą su HTTP 422 (Unprocessable Entity) būsenos kodu.
- Automatiškai generuoja JSON schemą iš jūsų Pydantic modelio, kuri naudojama interaktyviai API dokumentacijai (Swagger UI ir ReDoc) kurti.
Šis automatizuotas darbo srautas pašalina standartinį kodą, sumažina klaidas ir išlaiko jūsų duomenų apibrėžimus, validavimo taisykles ir dokumentaciją puikiai sinchronizuotus.
Pradedame: pagrindinis užklausos kūno validavimas
Pamatykime tai veiksme su paprastu pavyzdžiu. Įsivaizduokite, kad kuriame API el. prekybos platformai ir mums reikia galinio taško naujam produktui sukurti.
Pirmiausia apibrėžkite savo produkto duomenų formą naudodami Pydantic modelį:
# main.py
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional
# 1. Define the Pydantic model
class Item(BaseModel):
name: str
description: Optional[str] = None
price: float
tax: Optional[float] = None
app = FastAPI()
# 2. Use the model in a path operation
@app.post("/items/")
async def create_item(item: Item):
# At this point, 'item' is a validated Pydantic model instance
item_dict = item.dict()
if item.tax:
price_with_tax = item.price + item.tax
item_dict.update({"price_with_tax": price_with_tax})
return item_dict
Kas čia vyksta?
Funkcijoje `create_item` mes nurodėme `item` parametro tipą kaip mūsų Pydantic modelį `Item`. Tai yra signalas FastAPI atlikti validavimą.
Galiojanti užklausa:
Jei klientas siunčia POST užklausą į `/items/` su galiojančiu JSON kūnu, pavyzdžiui, tokiu:
{
"name": "Super Gadget",
"price": 59.99,
"tax": 5.40
}
FastAPI ir Pydantic sėkmingai jį validuos. Jūsų `create_item` funkcijoje `item` bus `Item` klasės egzempliorius. Jo duomenis galite pasiekti naudodami taško notaciją (pvz., `item.name`, `item.price`), o jūsų IDE suteiks visišką automatinį užbaigimą. API grąžins 200 OK atsakymą su apdorotais duomenimis.
Negaliojanti užklausa:
Dabar pažiūrėkime, kas nutinka, jei klientas siunčia neteisingai suformuotą užklausą, pavyzdžiui, siunčia kainą kaip eilutę, o ne slankiojo kablelio skaičių:
{
"name": "Faulty Gadget",
"price": "ninety-nine"
}
Jums nereikia rašyti nė vienos `if` sąlygos ar `try-except` bloko. FastAPI automatiškai pagauna validavimo klaidą iš Pydantic ir grąžina šį nuostabiai išsamų HTTP 422 atsakymą:
{
"detail": [
{
"loc": [
"body",
"price"
],
"msg": "value is not a valid float",
"type": "type_error.float"
}
]
}
Šis klaidos pranešimas yra nepaprastai naudingas klientui. Jis nurodo tikslią klaidos vietą (`body` -> `price`), žmogui suprantamą pranešimą ir mašinai suprantamą klaidos tipą. Tai yra automatinio validavimo galia.
Išplėstinis Pydantic validavimas FastAPI
Pagrindinis tipų tikrinimas yra tik pradžia. Pydantic siūlo gausybę įrankių sudėtingesnėms validavimo taisyklėms, kurios visos sklandžiai integruojasi su FastAPI.
Lauko apribojimai ir validavimas
Galite taikyti konkretesnius laukų apribojimus naudodami `Field` funkciją iš Pydantic (arba `Query`, `Path`, `Body` iš FastAPI, kurie yra `Field` poklasiai).
Sukurkime vartotojo registracijos modelį su kai kuriomis įprastomis validavimo taisyklėmis:
from pydantic import BaseModel, Field, EmailStr
class UserRegistration(BaseModel):
username: str = Field(
...,
min_length=3,
max_length=50,
regex="^[a-zA-Z0-9_]+$"
)
email: EmailStr # Pydantic has built-in types for common formats
password: str = Field(..., min_length=8)
age: Optional[int] = Field(
None,
gt=0,
le=120,
description="The age must be a positive integer."
)
@app.post("/register/")
async def register_user(user: UserRegistration):
return {"message": f"User {user.username} registered successfully!"}
Šiame modelyje:
- `username` turi būti nuo 3 iki 50 simbolių ilgio ir gali turėti tik raides, skaičius ir pabraukimo brūkšnius.
- `email` automatiškai validuojamas, siekiant užtikrinti, kad tai yra galiojantis el. pašto formatas, naudojant `EmailStr`.
- `password` turi būti bent 8 simbolių ilgio.
- `age`, jei pateiktas, turi būti didesnis už 0 (`gt`) ir mažesnis arba lygus 120 (`le`).
- `...` (daugtaškis) kaip pirmasis argumentas `Field` nurodo, kad laukas yra privalomas.
Įdėtieji modeliai
Realaus pasaulio API dažnai dirba su sudėtingais, įdėtais JSON objektais. Pydantic tai elegantiškai tvarko, leisdamas jums įterpti modelius į kitus modelius.
from typing import List
class Tag(BaseModel):
id: int
name: str
class Article(BaseModel):
title: str
content: str
tags: List[Tag] = [] # A list of other Pydantic models
author_id: int
@app.post("/articles/")
async def create_article(article: Article):
return article
Kai FastAPI gauna užklausą šiam galiniam taškui, jis patvirtins visą įdėtąją struktūrą. Jis užtikrins, kad `tags` yra sąrašas ir kad kiekvienas to sąrašo elementas yra galiojantis `Tag` objektas (t. y., jis turi sveikojo skaičiaus `id` ir eilutės `name`).
Pasirinktiniai validuotojai
Verslo logikai, kurios negalima išreikšti standartiniais apribojimais, Pydantic teikia `@validator` dekoratorių. Tai leidžia jums rašyti savo validavimo funkcijas.
Klasikinis pavyzdys yra slaptažodžio lauko patvirtinimas:
from pydantic import BaseModel, Field, validator
class PasswordChangeRequest(BaseModel):
new_password: str = Field(..., min_length=8)
confirm_password: str
@validator('confirm_password')
def passwords_match(cls, v, values, **kwargs):
# 'v' is the value of 'confirm_password'
# 'values' is a dict of the fields already processed
if 'new_password' in values and v != values['new_password']:
raise ValueError('Passwords do not match')
return v
@app.put("/user/password")
async def change_password(request: PasswordChangeRequest):
# Logic to change the password...
return {"message": "Password updated successfully"}
Jei validavimas nepavyksta (t. y., funkcija išmeta `ValueError`), Pydantic jį pagauna ir FastAPI konvertuoja į standartinį 422 klaidos atsakymą, lygiai taip pat, kaip su integruotomis validavimo taisyklėmis.
Įvairių užklausos dalių validavimas
Nors užklausų kūnai yra dažniausiai naudojami, FastAPI naudoja tuos pačius validavimo principus ir kitoms HTTP užklausos dalims.
Kelio ir užklausos parametrai
Galite pridėti išplėstinį validavimą kelio ir užklausos parametrams naudodami `Path` ir `Query` iš `fastapi`. Jie veikia lygiai taip pat kaip Pydantic `Field`.
from fastapi import FastAPI, Path, Query
from typing import List
app = FastAPI()
@app.get("/search/")
async def search(
q: str = Query(..., min_length=3, max_length=50, description="Your search query"),
tags: List[str] = Query([], description="Tags to filter by")
):
return {"query": q, "tags": tags}
@app.get("/files/{file_id}")
async def get_file(
file_id: int = Path(..., gt=0, description="The ID of the file to retrieve")
):
return {"file_id": file_id}
Jei bandysite pasiekti `/files/0`, FastAPI grąžins 422 klaidą, nes `file_id` nepavyksta `gt=0` (daugiau nei 0) validavimo. Panašiai, užklausa `/search/?q=ab` nepavyks dėl `min_length=3` apribojimo.
Gracingas validavimo klaidų tvarkymas
Numatytasis FastAPI 422 klaidos atsakymas yra puikus, tačiau kartais reikia jį pritaikyti pagal konkretų standartą arba pridėti papildomą registravimą. FastAPI tai palengvina su savo išimčių valdymo sistema.
Galite sukurti pasirinktinį išimčių tvarkyklę `RequestValidationError`, kuri yra specifinis išimties tipas, kurį FastAPI išmeta, kai Pydantic validavimas nepavyksta.
from fastapi import FastAPI, Request, status
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
app = FastAPI()
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
# You can log the error details here
# print(exc.errors())
# print(exc.body)
# Customize the response format
custom_errors = []
for error in exc.errors():
custom_errors.append(
{
"field": ".".join(str(loc) for loc in error["loc"]),
"message": error["msg"],
"type": error["type"]
}
)
return JSONResponse(
status_code=status.HTTP_400_BAD_REQUEST,
content={"error": "Validation Failed", "details": custom_errors},
)
# Add an endpoint that can fail validation
class Item(BaseModel):
name: str
price: float
@app.post("/items/")
async def create_item(item: Item):
return item
Naudojant šią tvarkyklę, negaliojanti užklausa dabar gaus 400 Bad Request atsakymą su jūsų pasirinktine JSON struktūra, suteikiant jums visišką kontrolę virš klaidos formato, kurį atskleidžia jūsų API.
Geriausios Pydantic modelių naudojimo praktikos FastAPI
Norėdami sukurti keičiamo dydžio ir lengvai prižiūrimas programas, apsvarstykite šias geriausias praktikas:
- Laikykitės DRY (Don't Repeat Yourself) principo: Naudokite modelių paveldėjimą, kad išvengtumėte pasikartojimo. Sukurkite bazinį modelį su bendrais laukais, tada išplėskite jį specifiniams naudojimo atvejams, tokiems kaip kūrimas (kuris gali praleisti `id` ir `created_at` laukus) ir skaitymas (kuris apima visus laukus).
- Atskirkite įvesties ir išvesties modelius: Duomenys, kuriuos priimate kaip įvestį (`POST`/`PUT`), dažnai skiriasi nuo duomenų, kuriuos grąžinate (`GET`). Pavyzdžiui, niekada neturėtumėte grąžinti vartotojo slaptažodžio maišos API atsakyme. Naudokite `response_model` parametrą savo kelio operacijos dekoratoriuje, kad apibrėžtumėte konkretų Pydantic modelį išvesties duomenims, užtikrindami, kad jautrūs duomenys niekada nebūtų netyčia atskleisti.
- Naudokite specifinius duomenų tipus: Pasinaudokite gausiu Pydantic specialiųjų tipų rinkiniu, tokiu kaip `EmailStr`, `HttpUrl`, `UUID`, `datetime` ir `date`. Jie suteikia integruotą validavimą įprastiems formatams, todėl jūsų modeliai tampa tvirtesni ir išraiškingesni.
- Konfigūruokite modelius su `Config` klase: Pydantic modelius galima pritaikyti per vidinę `Config` klasę. Pagrindinis nustatymas duomenų bazės integravimui yra `from_attributes=True` (anksčiau Pydantic v1 buvo `orm_mode=True`), kuris leidžia modeliui būti užpildytam iš ORM objektų (tokių kaip SQLAlchemy ar Tortoise ORM) pasiekiant atributus, o ne žodyno raktus.
Išvada
Sklandi Pydantic integracija neabejotinai yra viena iš pagrindinių FastAPI savybių. Ji pakelia API kūrimą, automatizuodama svarbias, bet dažnai nuobodžias duomenų validavimo, serializavimo ir dokumentavimo užduotis. Apibrėždami savo duomenų formas vieną kartą su Pydantic modeliais, gaunate daug privalumų: tvirtą saugumą, pagerintą duomenų vientisumą, puikią kūrėjo patirtį jūsų API vartotojams ir lengviau prižiūrimą kodo bazę sau.
Perkeldami validavimo logiką iš savo verslo kodo į deklaratyvius duomenų modelius, sukuriate API, kurios yra ne tik greitai veikiančios, bet ir greitai kuriamos, lengvai suprantamos ir saugios naudoti. Taigi, kitą kartą, kai pradėsite naują Python API projektą, pasinaudokite FastAPI ir Pydantic galia, kad sukurtumėte tikrai profesionalaus lygio paslaugas.